import {WatermarkOptions} from "../types";
import {getTextSize, randomId} from "./util";

interface InterfaceText {
    x: number
    y: number
    text: string
    width: number
}

export default class Watermark {
    // 渲染配置
    watermarkOption?: WatermarkOptions
    // 渲染文本
    watermarkText?: string | string[]
    // 唯一的节点id
    watermarkId?: string
    watermarkClass: string
    // 监听器
    observer?: MutationObserver
    // 水印节点
    watermarkDom?: Element
    // 当前是渲染显示了水印
    visible: boolean

    static observerOptions = {
        childList: true,  // 观察目标子节点的变化，是否有添加或者删除
        attributes: true, // 观察属性变动
        subtree: true     // 观察后代节点，默认为 false
    }

    static observerBodyOptions = {
        childList: true,
    }

    constructor() {
        this.watermarkClass = `watermark-${randomId(6)}`
        this.visible = false
    }

    render(watermarkText: string | string[], watermarkOption?: WatermarkOptions) {
        watermarkOption = watermarkOption || {}
        this.watermarkOption = watermarkOption

        const {
            rotate = '45',
            opacity = '0.1',
            fontSize = '16px',
            fontWeight = 'normal',
            padding = 20,
            space = 8,
            color = 'rgb(0,0,0)',
        } = watermarkOption

        if(this.watermarkId && document.querySelector('#'+this.watermarkId)) {
            this.removeWatermark()
        }

        const dom = document.createElement('div')
        dom.id = this.createDomId()
        dom.classList.add(this.watermarkClass)
        dom.style.width = '100vw'
        dom.style.height = '100vh'
        dom.style.position = 'fixed'
        dom.style.zIndex = '9999'
        dom.style.left = '0'
        dom.style.top = '0'
        dom.style.pointerEvents = 'none'

        if(typeof watermarkText === "string") {
            watermarkText = [watermarkText]
        }

        this.watermarkText = watermarkText

        let bgSetting = {
            height: 0,
            width: 0,
            text: [] as InterfaceText[],
            g: {
                x: 0,
                y: 0,
                centerX: 0,
                centerY: 0,
                transform: '',
            },
            contentWidth: 0,
            contentHeight: 0,
            textStyle: '',
        }

        bgSetting = watermarkText.reduce((a, b) => {
            const rect = getTextSize(b, watermarkOption)

            a.text.push({
                x: 0,
                y: a.contentHeight + space,
                text: b,
                width: rect.width,
            })
            a.contentHeight += (rect.height + space)
            a.contentWidth = Math.max(a.contentWidth, rect.width)

            return a
        }, bgSetting)

        // 计算对角线长度
        bgSetting.width = Math.hypot(bgSetting.contentWidth + 2*padding, bgSetting.contentHeight + 2*padding)
        // 高度直接使用对角线长度
        bgSetting.height = bgSetting.width

        // 文本居中
        bgSetting.text.forEach(v => {
            v.x = (bgSetting.contentWidth - v.width) / 2
        })

        // 内容居中
        bgSetting.g.x = (bgSetting.width - bgSetting.contentWidth) / 2
        bgSetting.g.y = (bgSetting.height - bgSetting.contentHeight) / 2
        bgSetting.g.centerX = bgSetting.width/2
        bgSetting.g.centerY = bgSetting.height/2
        bgSetting.g.transform = `rotate(${rotate},${bgSetting.g.centerX},${bgSetting.g.centerY}),translate(${bgSetting.g.x},${bgSetting.g.y})`

        bgSetting.textStyle = `font-weight: ${fontWeight};font-size: ${fontSize};opacity: ${opacity};font-family: \\'Courier New\\', Consolas, monospace;`

        const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${bgSetting.width}" height="${bgSetting.height}"><g transform="${bgSetting.g.transform}">${
            bgSetting.text.map(({x, y, text}) => {
                return `<text stroke="${color}" style="${bgSetting.textStyle}" x="${x}" y="${y}">${text}</text>`
            }).join('')
        }</g></svg>`

        dom.style.backgroundImage = `url('data:image/svg+xml;utf8,${svg}')`

        document.body.appendChild(dom)
        this.watermarkDom = dom

        const observer = this.initObserver()
        observer.observe(dom, Watermark.observerOptions)
        observer.observe(document.body, Watermark.observerBodyOptions)
        this.visible = true
    }

    initObserver() {
        this.observer = new MutationObserver(mutationsList => {
            for(const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    const removedNodes = mutation.removedNodes
                    if(Array.from(removedNodes).some(v => (v as Element).id === this.watermarkId)) {
                        if(this.watermarkText) {
                            this.resetWatermark(this.watermarkText)
                        }
                    }
                } else if (mutation.type === 'attributes') {
                    if(this.watermarkText) {
                        this.resetWatermark(this.watermarkText)
                    }
                }
            }
        })
        return this.observer
    }

    createDomId() {
        this.watermarkId = `watermark-${randomId(6)}`
        return this.watermarkId
    }

    resetWatermark(watermarkText: string | string[]) {
        this.removeWatermark()
        this.watermarkText = watermarkText
        if(this.watermarkText) {
            this.render(this.watermarkText, this.watermarkOption)
        }
    }

    removeWatermark() {
        if(this.observer) {
            this.observer.disconnect()
        }

        const domList = document.querySelectorAll('.' + this.watermarkClass)

        for (const dom of domList) {
            document.body.removeChild(dom)
        }

        this.visible = false
    }
}
